﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ChisMethodsHomework12._10._11
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public void SeidelMethod(double[] v, int n, int Smax, ref int S, ref double Eps,double Epsmax,ref int f)
        {
            double h = 1.0 / (n);
            double b = 5;
            double a = -1.0 / (2.0 / (h * h) + 7);
            double[] v_new = new double[n + 1];
            double eps_cur = 0;
            double x_new;
            f = 0;
            v[0] = v_new[0] = 1;
            v[n] = v_new[0] = 13;
            Eps = 0;
            while (f == 0)
            {
                Eps = 0;
                for (int i = 1; i < n; i++)
                {
                    x_new = b - n * n * (v[i - 1] + v[i + 1]);
                    x_new = a * x_new;
                    eps_cur = Math.Abs(v[i] - x_new);
                    if (eps_cur > Eps)
                    {
                        Eps = eps_cur;
                    }
                    v[i] = x_new;
                }
                S = S + 1;
                if (Eps < Epsmax)
                    f = 1;
                if (S > Smax)
                    f = 2;
            }
        }
        public void UpperRelMethod(double[] v, int n, int Smax, ref int S, ref double eps, double eps_max,ref int cause, double w)
        {
            S = 0;
            double h = 1.0 / (n - 1.0);
            double eps_cur = 0;
            double v_old;
            double v_new;
            bool f = false;
            for (int i = 0; i < n; i++)
                v[i] = 0;
            v[0] = 1;
            v[n - 1] = 13;
            while (!f)
            {
                eps = 0;
                for (int i = 1; i < n - 1; i++)
                {
                    v_old = v[i];
                    v_new = (1 - w) * (-7 - 2 / (h * h)) * v[i] + w * 5;
                    for (int j = 0; j < n + 1; j++)
                    {
                        int tmp = (i - j) > 0 ? (i - j) : (j - i);
                        if (tmp == 1)
                            v_new -= w * v[j] / (h * h);
                    }
                    v_new = v_new / (-7 - 2 / (h * h));
                    eps_cur = (v_old - v_new) > 0 ? (v_old - v_new) : (v_new - v_old);
                    if (eps_cur > eps)
                        eps = eps_cur;
                    v[i] = v_new;
                }
                S++;
                if ((eps < eps_max) || (S >= Smax))
                    f = true;
            }
            if (eps < eps_max)
                cause = 1;
            else if (S >= Smax)
                cause = 2;
        }
        public void YakobiMethod(double[] v, int n,ref int S, int SMAX,ref double Eps, double EpsMin,ref int cause)
{
  double h = 1.0 /( n - 1);
  double b = 5;
  double a = 1.0 / ( 2.0 + 7 * h * h );
  double [] v_new = new double [n];
  bool f = true;
  double eps_cur;
  v[n - 1] = 13;
  v[0] = 1;
  v_new[0] = 1;
  v_new[n - 1] = 13;
  while (f)
  {

    Eps = 0.0;
    for (int i = 1; i < n - 1; i++)
	{
	  v_new[i] = a * ((v[i - 1] + v[i + 1])-b * h * h);
	  eps_cur = System.Math.Abs (v_new[i] - v[i]);
	  if (eps_cur > Eps)
	  {
	    Eps = eps_cur;
	  }
	}
	v_new.CopyTo (v, 0);
	S++;
	if (Eps < EpsMin) 
	{
	  cause = 1;
      f = false;

	}
	else if (S > SMAX)
	{
	  cause = 2;
        f = false;
	}
  }
}
        private void button1_Click(object sender, EventArgs e)
        {
            // Число узлов
            int n = -1;
            // Массив для хранения значений функции
            double[] v=null;
            // Переменные для критерия останова
            double eps = -1,min_eps = -1.0;
            int numOfSteps = 0, maxSteps = -1;
            int Prichina = -1;

            n = Convert.ToInt32(textBox1.Text);
            v = new double[n];
            for (int i = 0; i < n; i++)
                v[i] = 0.0;
            v[0] = 1;
            v[n - 1] = 13;

            min_eps = Convert.ToDouble(textBox5.Text);
            maxSteps = Convert.ToInt32(textBox4.Text);

            int methodType = 0;
            if (radioButton1.Checked) methodType = 0;
            if (radioButton2.Checked) methodType = 1;
            if (radioButton3.Checked) methodType = 2;

            switch (methodType)
            {
                case 0:
                    {
                        SeidelMethod (v,n - 1,maxSteps,ref numOfSteps, ref eps, min_eps,ref Prichina);
                        break;
                    }
                case 1:
                      YakobiMethod(v,n,ref numOfSteps,maxSteps,ref eps,min_eps,ref Prichina);
                      break;

                case 2:
                      {
                          UpperRelMethod (v,n,maxSteps,ref numOfSteps,ref eps, min_eps, ref Prichina,1.0);
                          break;
                      }
                default:
                      break;
                    
                    
            }

            // Вывод на экран
            textBox2.Text = numOfSteps.ToString();
            textBox3.Text = eps.ToString("G4"); 
            textBox4.Text = maxSteps.ToString();
            textBox5.Text = min_eps.ToString();

            //Определение точного решения
            double C1, C2;
            C1 = 1.0 + 5.0 / 7.0;
            C2 = (13.0 + 5.0/7.0 - C1 *Math.Cosh(Math.Sqrt(7))) / Math.Sinh(Math.Sqrt(7));
            double[] u; // точное решение
            u = new double[n];
            for (int i = 0; i < n; i++)
            {
                u[i] = -5.0 / 7.0 +  C1 * Math.Cosh(Math.Sqrt(7.0) * (i / (n - 1.0))) +
                    C2 * Math.Sinh(Math.Sqrt(7.0) * (i / (n - 1.0)));
            }
            
            // Определим норму расхождения численного и тестового решения
            double[] uv = new double[n];
            for (int i = 0; i < n; i++)
            {
                uv[i] = Math.Abs(u[i] - v[i]);
            }
            double Norm = 0.0;
            for (int i = 0; i < n; i++)
            {
                if (Norm < uv[i]) { Norm = uv[i]; }
            }
            if (Prichina == 1)
            {
                label7.Text = "точность ||z||="+Norm.ToString("");
            }
            if (Prichina == 2)
            {
                label7.Text = "число шагов ||z||=" + Norm.ToString("");
            }
        }
    }
}
